package tmt.usercenter.web.configure.security.bean;

import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Component
public class MyApprovalHandler extends ApprovalStoreUserApprovalHandler {

	private int approvalExpirySeconds = -1;
	private String scopePrefix = OAuth2Utils.SCOPE_PREFIX;
	private String scopeKey = "scopes";
	private ApprovalStore approvalStore;

	public MyApprovalHandler(ApprovalStore approvalStore, ClientDetailsService clientDetailsService) {
		this.approvalStore = approvalStore;

		setApprovalStore(approvalStore);
		setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
		setClientDetailsService(clientDetailsService);
	}

	public void setApprovalExpirySeconds(int seconds) {
		this.approvalExpirySeconds = seconds;
	}

	public void setScopeKey(String key) {
		this.scopeKey = key;
	}

	private Date computeExpiry() {
		Calendar expiresAt = Calendar.getInstance();
		if (approvalExpirySeconds == -1) { // use default of 1 month
			expiresAt.add(Calendar.MONTH, 1);
		} else {
			expiresAt.add(Calendar.SECOND, approvalExpirySeconds);
		}
		return expiresAt.getTime();
	}

	/** 自定义前台 scopes 提交结果 */
	public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
		return myHandler(authorizationRequest, userAuthentication);
	}

	private AuthorizationRequest myHandler(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {

		Set<String> requestedScopes = authorizationRequest.getScope();
		Set<String> approvedScopes = new HashSet<>();
		Set<Approval> approvals = new HashSet<>();

		HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		List<String> scopesList = Arrays.asList(httpServletRequest.getParameterValues(scopeKey));
		Date expiry = computeExpiry();
		Map<String, String> approvalParameters = new HashMap<>();
		for (String requestedScope : requestedScopes) {

			if (scopesList.contains(requestedScope)) {
				// 允许，修改 authorizeRequest.approvalParameters<scope.user_info, true>
				approvalParameters.put(scopePrefix + requestedScope, "true");
				approvedScopes.add(requestedScope);
				approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
						requestedScope, expiry, Approval.ApprovalStatus.APPROVED));
			} else {
				// 不允许
				approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
						requestedScope, expiry, Approval.ApprovalStatus.DENIED));
			}

		}
		approvalStore.addApprovals(approvals);
		boolean approved;
		authorizationRequest.setApprovalParameters(approvalParameters);
		authorizationRequest.setScope(approvedScopes);
		if (approvedScopes.isEmpty() && !requestedScopes.isEmpty()) {
			approved = false;
		} else {
			approved = true;
		}
		authorizationRequest.setApproved(approved);
		return authorizationRequest;
	}

	private AuthorizationRequest defaultHandler(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
		// Get the approved scopes
		Set<String> requestedScopes = authorizationRequest.getScope();
		Set<String> approvedScopes = new HashSet<>();
		Set<Approval> approvals = new HashSet<>();

		Date expiry = computeExpiry();

		// Store the scopes that have been approved / denied
		Map<String, String> approvalParameters = authorizationRequest.getApprovalParameters();
		for (String requestedScope : requestedScopes) {
			String approvalParameter = scopePrefix + requestedScope;
			String value = approvalParameters.get(approvalParameter);
			value = value == null ? "" : value.toLowerCase();
			if ("true".equals(value) || value.startsWith("approve")) {
				approvedScopes.add(requestedScope);
				approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
						requestedScope, expiry, Approval.ApprovalStatus.APPROVED));
			} else {
				approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
						requestedScope, expiry, Approval.ApprovalStatus.DENIED));
			}
		}
		approvalStore.addApprovals(approvals);

		boolean approved;
		authorizationRequest.setScope(approvedScopes);
		if (approvedScopes.isEmpty() && !requestedScopes.isEmpty()) {
			approved = false;
		} else {
			approved = true;
		}
		authorizationRequest.setApproved(approved);
		return authorizationRequest;
	}

}
